package com.myapp.interceptor;


import com.myapp.context.TenantContext;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

/**
 * 一个简单的分表插件
 */
@Intercepts({@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class, Integer.class})})
public class UserLogInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
        StatementHandler delegate = getFieldValue(handler, "delegate");
        MappedStatement mappedStatement = getFieldValue(delegate, "mappedStatement");
        BoundSql boundsql = handler.getBoundSql();
        String sqlId = mappedStatement.getId();

        if (sqlId.startsWith("com.myapp.dao.UserLogMapper.")) {
            String sql = boundsql.getSql();
            // 获取tenantId
            String tenantId = TenantContext.getTenantId();
            sql = sql.replace("$tenantId$", tenantId);
            setFieldValue(boundsql, "sql", sql);
        }
        return invocation.proceed();
    }

    private <T> T getFieldValue(Object handler, String name) {
        Field delegateField = ReflectionUtils.findField(handler.getClass(), name);
        delegateField.setAccessible(true);
        return (T) ReflectionUtils.getField(delegateField, handler);
    }

    private void setFieldValue(Object obj, String fieldName, Object fieldValue) {
        Field field = ReflectionUtils.findField(obj.getClass(), fieldName);
        if (field != null) {
            try {
                field.setAccessible(true);
                field.set(obj, fieldValue);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}
